// Copyright (c) 2009 Hypirinha contributers
// This program is made available under the terms of the MIT License.
package org.hypirinha.html.output.dom;

import org.w3c.dom.Document;

import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathFactory;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.namespace.NamespaceContext;
import java.util.Map;
import java.util.HashMap;
import java.util.Iterator;

class XPathEvaluator {

    XPath xPath = XPathFactory.newInstance().newXPath();
    private Document document;

    public XPathEvaluator(Document document, NamespaceMapping... mappings) {
        this.document = document;
        final Map<String, NamespaceMapping> namespaceMappings = new HashMap<String, NamespaceMapping>();
        for (NamespaceMapping mapping : mappings) {
            namespaceMappings.put(mapping.getPrefix(), mapping);
        }
        xPath.setNamespaceContext(new NamespaceContext() {
            public String getNamespaceURI(String s) {
                return namespaceMappings.get(s).getUri();
            }

            public String getPrefix(String s) {
                throw new UnsupportedOperationException("This is a one-way namespace lookup");
            }

            public Iterator getPrefixes(String s) {
                throw new UnsupportedOperationException("This is a one-way namespace lookup");
            }
        });
    }

    public boolean bool(String xPathExpression) {
        try {
            return (Boolean) xPath.evaluate(xPathExpression, document, XPathConstants.BOOLEAN);
        } catch (XPathExpressionException e) {
            throw new RuntimeException(e);
        }
    }

    public int integer(String xPathExpression) {
        try {
            return ((Double) xPath.evaluate(xPathExpression, document, XPathConstants.NUMBER)).intValue();
        } catch (XPathExpressionException e) {
            throw new RuntimeException(e);
        }
    }

    public String string(String xPathExpression) {
        try {
            return (String) xPath.evaluate(xPathExpression, document, XPathConstants.STRING);
        } catch (XPathExpressionException e) {
            throw new RuntimeException(e);
        }
    }

    public static XPathEvaluator xPath(Document document, NamespaceMapping... mappings) {
        return new XPathEvaluator(document, mappings);
    }

    public static class NamespaceMapping {
        String prefix;
        String uri;

        public NamespaceMapping(String prefix, String uri) {
            this.prefix = prefix;
            this.uri = uri;
        }

        public String getPrefix() {
            return prefix;
        }

        public String getUri() {
            return uri;
        }

        public static NamespaceMapping namespace(String prefix, String uri) {
            return new NamespaceMapping(prefix, uri);
        }
    }
}
